package com.pingan.pastry.register;

import com.pingan.pastry.InvokerBucket;

import com.pingan.pastry.Invoker;
import com.pingan.pastry.PastryManager;
import com.pingan.pastry.VerifyInvoker;
import com.pingan.pastry.common.annotation.Fn;
import com.pingan.pastry.common.annotation.Svc;
import com.pingan.pastry.validator.BeanProvider;
import com.pingan.pastry.validator.Rule;
import com.pingan.pastry.validator.RuleBuilder;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Map;

@Component
public class InvokerRegister implements ApplicationListener<ContextRefreshedEvent> {

    private PastryManager pastryManager = new PastryManager();

    @Resource
    private BeanProvider beanProvider;


    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        System.out.println("监听spring 启动完成事件...");
        RuleBuilder ruleBuilder = new RuleBuilder(beanProvider);
        Map<String, Object> beanMap = beanProvider.getBeansWithAnnotation(Svc.class);
        for (String key : beanMap.keySet()) {
            System.out.println("key: " + key + " == value: " + beanMap.get(key));
            Object service = beanMap.get(key);
            Class<?>[] interfaces = service.getClass().getInterfaces();
            Class<?> interfaceClass = interfaces[0];

            if (interfaceClass.isInterface()) {
                Method[] methods = interfaceClass.getMethods();
                for (Method method : methods) {
                    Fn fn = method.getAnnotation(Fn.class);
                    if (fn != null) {
                        registerInvoker(ruleBuilder, service, interfaceClass, method);
                    }
                }
            }
        }
    }

    private void registerInvoker(RuleBuilder ruleBuilder, Object service, Class<?> interfaceClass, Method method) {
        String invokerName = pastryManager.obtainClassName(method, "Invoker");
        try {
            Class<?> invokerClass = pastryManager.createInvoker(invokerName);
            Invoker invoker = (Invoker) invokerClass.newInstance();
            invoker.setTarget(service);
            String uri = calculateURI(interfaceClass, method);
            VerifyInvoker verifyInvoker = obtainVerifyInvoker(ruleBuilder, uri, invoker);
            InvokerBucket.invokerMap.put(uri, verifyInvoker);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

    private VerifyInvoker obtainVerifyInvoker(RuleBuilder ruleBuilder, String uri, Invoker invoker) {
        Rule rule = ruleBuilder.build(uri);
        VerifyInvoker verifyInvoker = new VerifyInvoker(invoker);
        verifyInvoker.setRule(rule);
        return verifyInvoker;
    }

    private String calculateURI(Class<?> interfaceClass, Method method) {
        String uri = null;
        Svc svc = interfaceClass.getAnnotation(Svc.class);
        if (svc != null) {
            uri = svc.value() + "/" + method.getName();
        }
        return uri;
    }

}
